#ifndef MEMQUEUE_H_
#define MEMQUEUE_H_

#include <assert.h>
#include "SafeQueue.hh"
#include "Synchronized.hh"
#include <lagniappe/RCon.h>
#include <map>
#include <vector>

class memQueue : public Synchronized
{
private:
    std::vector<SafeQueue<lagniappe::RCon *> *> coreQueues;
    //std::map<std::string, SafeQueue<lagniappe::RCon *> *> coreQueues;
    uint32_t work;
    std::vector<SafeQueue<lagniappe::RCon *> *>::iterator vecIter;
public:
    virtual uint32_t getCount() {return work;}
    memQueue() : work(0) {}
    virtual ~memQueue() {}
    virtual unsigned long getFreeQueues() {
        return 20 - coreQueues.size();
    }
    void registerQueue(uint32_t queueName) {
        Synchronized::Scope mutex(this);
        //if(coreQueues.find(queueName) == coreQueues.end()) {
        if(queueName == 0) {
          if(coreQueues.size() == 0) {
            coreQueues.push_back(new SafeQueue<lagniappe::RCon *>());
          }
          else {
            coreQueues.at(queueName) = new SafeQueue<lagniappe::RCon *>();
          }
        }
        else if(queueName >= coreQueues.size()) {
          coreQueues.resize(queueName+1);
	  coreQueues.at(queueName) = new SafeQueue<lagniappe::RCon *>();
	}
	else {
	  coreQueues.at(queueName) = new SafeQueue<lagniappe::RCon *>();
	}
	vecIter = coreQueues.begin();
        notifyAll();
    }
    void deleteQueue(uint32_t queueName) {
        SafeQueue<lagniappe::RCon *> * target = coreQueues[queueName];
        delete target;
        coreQueues[queueName] = NULL;
        //coreQueues.erase(queueName);
    }
    //void push(lagniappe::RCon * rc) {assert(rc != NULL); coreQueue.push(rc);}
    void push(lagniappe::RCon *rc) {
        //assert(!coreQueues.empty());
        waitForQueues();
	//std::cerr << "\tAnnouncing work for port: " << rc->getPort() << std::endl;
        announceWork();
        //std::cerr<< rc->getPort() << std::endl;
        SafeQueue<lagniappe::RCon *> * target = coreQueues.at(rc->getPort());
        assert(target != NULL);
	//std::cerr << "\t(" << this << ")Work announced, pushing on: " << target << std::endl;
	//std::cerr << "\t(" << this << ")coreQueues size: " << coreQueues.size() << std::endl;
        target->push(rc);
	//std::cerr << "\tPushed work onto queue: " << target << std::endl;
    }
    //lagniappe::RCon * pop() {lagniappe::RCon * rc = coreQueue.pop(); return rc;}
    lagniappe::RCon * pop() {
        waitForQueues();
        SafeQueue<lagniappe::RCon *> * target = *vecIter;
        while(target == NULL) {
          vecIter++;
          if(vecIter == coreQueues.end()) {
            vecIter = coreQueues.begin();
          }
          target = *vecIter;
        }
        lagniappe::RCon * ret = NULL;
        while(ret == NULL) {
            //std::cerr << "\t\tAbout to wait for work." << std::endl;
            waitForWork();
            ret = target->peek();
            if(ret != NULL && ret->getOp()->pred(ret->getPort())) {
		//std::cerr << "\t\tGot inside" << std::endl;
                target->pop();
                takeWork();
                vecIter++;
                if(vecIter == coreQueues.end()) {
                    vecIter = coreQueues.begin();
                }
            }
            else {
		//std::cerr << "Got here because: " << ret << std::endl;
		ret = NULL;
		vecIter++;
                if(vecIter == coreQueues.end()) {
                    vecIter = coreQueues.begin();
                }
                target = *vecIter;
		while(target == NULL) {
			vecIter++;
			if(vecIter == coreQueues.end()) {
				vecIter = coreQueues.begin();
			}
			target = *vecIter;
		}
		//std::cerr << "\t(" << this << ")Found a real queue: " << target << ":" << coreQueues.size() << std::endl;
            }
        }
        return ret;
    }
    void waitForQueues() {
        Synchronized::Scope mutex(this);
        while(coreQueues.empty()) {
            wait();
        }
    }
    void waitForWork() {
        Synchronized::Scope mutex(this);
        while(work == 0) {
            wait();
        }
    }
    void announceWork() {
        Synchronized::Scope mutex(this);
        work++;
        notify();
    }
    void takeWork() {
        Synchronized::Scope mutex(this);
        work--;
        assert(work >= 0);
        notify();
    }
    //bool empty() {}
};

#endif // MEMQUEUE_H_
